<template>
  <view>
    <ArcoInput
      v-model="inputValue"
      :class="cls"
      type="text"
      :allow-clear="allowClear"
      :placeholder="placeholder"
    >
      <template #append>
        <ArcoButton
          :size="mergedSize"
          :class="`${prefixCls}-step-button`"
          :disabled="mergedDisabled || isMin"
          @click="handleStepButton('minus')"
        >
          <template #icon>
            <a-icon name="jia"></a-icon>
          </template>
        </ArcoButton>
      </template>
      <template #prepend>
        <ArcoButton
          :size="mergedSize"
          :class="`${prefixCls}-step-button`"
          :disabled="mergedDisabled || isMin"
          @click="handleStepButton('plus')"
        >
          <template #icon>
            <a-icon name="jian"></a-icon>
          </template>
        </ArcoButton>
      </template>
    </ArcoInput>
  </view>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, ref, toRefs } from "vue";
import ArcoInput from "../arco-input/index.vue";
import { Size } from "@/ArcoUni/utils/interface";
import { useSize } from "@/ArcoUni/hook/use-size";
import { useFormItem } from "@/ArcoUni/hook/use-form-item";
import { isNumber, isUndefined } from "@/utils/is";
import aIcon from "../arco-icon/index.vue";
import NP from "number-precision";
import ArcoButton from "../arco-button/index.vue";

type StepMethods = "minus" | "plus";

export default defineComponent({
  name: "InputNumber",
  components: {
    ArcoInput,
    aIcon,
    ArcoButton,
  },
  props: {
    /**
     * @zh 绑定值
     * @en Value
     */
    modelValue: Number,
    /**
     * @zh 默认值（非受控模式）
     * @en Default value (uncontrolled mode)
     */
    defaultValue: Number,
    /**
     * @zh 模式（`embed`：按钮内嵌模式，`button`：左右按钮模式）
     * @en Mode (`embed`: button embedded mode, `button`: left and right button mode)
     * @values 'embed', 'button'
     */
    mode: {
      type: String as PropType<"embed" | "button">,
      default: "embed",
    },
    /**
     * @zh 数字精度
     * @en Precision
     */
    precision: Number,
    /**
     * @zh 数字变化步长
     * @en Number change step
     */
    step: {
      type: Number,
      default: 1,
    },
    /**
     * @zh 是否禁用
     * @en Whether to disable
     */
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * @zh 是否为错误状态
     * @en Whether it is an error state
     */
    error: {
      type: Boolean,
      default: false,
    },
    /**
     * @zh 最大值
     * @en Max
     */
    max: {
      type: Number,
      default: Infinity,
    },
    /**
     * @zh 最小值
     * @en Min
     */
    min: {
      type: Number,
      default: -Infinity,
    },
    /**
     * @zh 定义输入框展示值
     * @en Define the display value of the input
     */
    formatter: {
      type: Function,
    },
    /**
     * @zh 从 `formatter` 转换为数字，和 `formatter` 搭配使用
     * @en Convert from `formatter` to number, and use with `formatter`
     */
    parser: {
      type: Function,
    },
    /**
     * @zh 输入框提示文字
     * @en Input prompt text
     */
    placeholder: String,
    /**
     * @zh 输入框大小
     * @en Input size
     * @values 'mini','small','medium','large'
     * @defaultValue 'medium'
     */
    size: {
      type: String as PropType<Size>,
    },
    /**
     * @zh 是否允许清空输入框
     * @en Whether to allow the input to be cleared
     */
    allowClear: {
      type: Boolean,
      default: false,
    },
    /**
     * @zh 触发 `v-model` 的事件
     * @en Trigger event for `v-model`
     */
    modelEvent: {
      type: String as PropType<"change" | "input">,
      default: "change",
    },
    /**
     * @zh 只读
     * @en Readonly
     * @version 2.33.1
     */
    readOnly: {
      type: Boolean,
      default: false,
    },
    /**
     * @zh 内部 input 元素的属性
     * @en Attributes of inner input elements
     * @version 2.52.0
     */
    inputAttrs: {
      type: Object,
    },
  },
  emits: ["update:modelValue", "change"],
  setup(props, { emit }) {
    const prefixCls = "arco-input-number";
    const { size, disabled } = toRefs(props);
    const {
      mergedSize: _mergedSize,
      mergedDisabled,
      eventHandlers,
    } = useFormItem({
      size,
      disabled,
    });

    console.log(eventHandlers, "wi");

    const { mergedSize } = useSize(_mergedSize);

    const mergedPrecision = computed(() => {
      if (isNumber(props.precision)) {
        const decimal = `${props.step}`.split(".")[1];
        const stepPrecision = (decimal && decimal.length) || 0;
        return Math.max(stepPrecision, props.precision);
      }
      return undefined;
    });

    const getStringValue = (number: number | undefined) => {
      if (!isNumber(number)) {
        return "";
      }

      const numString = mergedPrecision.value
        ? number.toFixed(mergedPrecision.value)
        : String(number);
      return props.formatter?.(numString) ?? numString;
    };

    const inputValue = ref(
      getStringValue(props.modelValue ?? props.defaultValue),
    );

    const valueNumber = computed(() => {
      if (!inputValue.value) {
        return undefined;
      }
      const number = Number(
        props.parser?.(inputValue.value) ?? inputValue.value,
      );
      return Number.isNaN(number) ? undefined : number;
    });

    const isMin = ref(
      isNumber(valueNumber.value) && valueNumber.value <= props.min,
    );
    const isMax = ref(
      isNumber(valueNumber.value) && valueNumber.value >= props.max,
    );

    const handleStepButton = (method: StepMethods) => {
      if (props.readOnly) return;

      nextStep(method);
    };

    const getLegalValue = (value: number | undefined): number | undefined => {
      if (isUndefined(value)) {
        return undefined;
      }

      if (isNumber(props.min) && value < props.min) {
        value = props.min;
      }

      if (isNumber(props.max) && value > props.max) {
        value = props.max;
      }

      return isNumber(mergedPrecision.value)
        ? NP.round(value, mergedPrecision.value)
        : value;
    };

    const updateNumberStatus = (number: number | undefined) => {
      let _isMin = false;
      let _isMax = false;
      if (isNumber(number)) {
        if (number <= props.min) {
          _isMin = true;
        }
        if (number >= props.max) {
          _isMax = true;
        }
      }
      if (isMax.value !== _isMax) {
        isMax.value = _isMax;
      }
      if (isMin.value !== _isMin) {
        isMin.value = _isMin;
      }
    };

    const nextStep = (method: StepMethods) => {
      if (
        mergedDisabled.value ||
        (method === "plus" && isMax.value) ||
        (method === "minus" && isMin.value)
      ) {
        return;
      }

      let nextValue: number | undefined;
      if (isNumber(valueNumber.value)) {
        nextValue = getLegalValue(NP[method](valueNumber.value, props.step));
      } else {
        nextValue = props.min === -Infinity ? 0 : props.min;
      }

      inputValue.value = getStringValue(nextValue);
      updateNumberStatus(nextValue);
      emit("update:modelValue", nextValue);
      emit("change", nextValue);
    };

    const cls = computed(() => [
      prefixCls,
      `${prefixCls}-mode-button`,
      `${prefixCls}-size-${mergedSize.value}`,
      {
        [`${prefixCls}-readonly`]: props.readOnly,
      },
    ]);

    return {
      cls,
      prefixCls,
      mergedDisabled,
      isMax,
      isMin,
      handleStepButton,
      inputValue,
      mergedSize,
    };
  },
});
</script>
